package cn.jrd.cordova.rfid;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import com.google.gson.Gson;
import com.nativec.tools.ModuleManager;
import com.nativec.tools.SerialPort;
import com.nativec.tools.SerialPortFinder;
import com.reader.base.CMD;
import com.reader.base.ReaderBase;
import com.reader.helper.InventoryBuffer;
import com.reader.helper.ReaderHelper;
import com.reader.helper.ReaderSetting;
import com.tools.Beeper;
import com.ui.base.PreferenceUtil;

import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CallbackContext;

import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * This class echoes a string called from JavaScript.
 */
public class RfidPlugin extends CordovaPlugin {

    private static final boolean DEBUG = true;
    /**
     * Constructor.
     */
    public RfidPlugin() {
        this.inventory6cWebViewReceiver = null;
    }

    private static Context mContext;

    public static Context getContext(){
        return mContext;
    }

    /**
     * 6c 标签存盘 Receiver for WebView
     */
    private BroadcastReceiver inventory6cWebViewReceiver;

    /**
     * 6c 标签存盘 CallbackContext
     */
    private CallbackContext inventory6cCallbackContext = null;

    /**
     * Stop the battery receiver and set it to null.
     */
    private void removeInventory6cListener() {
        if (this.inventory6cWebViewReceiver != null) {
            try {
                webView.getContext().unregisterReceiver(this.inventory6cWebViewReceiver);
                this.inventory6cWebViewReceiver = null;
            } catch (Exception e) {
                LOG.e("Inventory 6c", "Error unregistering Inventory 6c receiver: "
                        + e.getMessage(), e);
            }
        }
    }

    private Socket tcpSocket = null;
    private BluetoothSocket btSocket = null;
    public void setTcpSocket(Socket socket) {
        this.tcpSocket = socket;
    }
    public void setBtSocket(BluetoothSocket socket) {
        this.btSocket = socket;
    }

    private static SerialPort serialPort = null;

//    private static SerialPortFinder serialPortFinder;

    /**
     * 获取所有串口数据
     */
    private static JSONArray devicesJSONArray;

    /**
     * 根据串口号获取path
     */
//    private static JSONArray devicesPathJSONArray;
    private static String[] devicesPath;

    /**
     * 端口
     */
    private static List<Integer> posPort = Arrays.asList(115200, 38400);

    @Override
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
        super.initialize(cordova, webView);

        mContext = this.cordova.getActivity().getApplicationContext();
        /*
            初始化 PreferenceUtil
         */
        PreferenceUtil.init(mContext);
        /*
            声音初始化
         */
        Beeper.init(mContext);

        SerialPortFinder serialPortFinder = new SerialPortFinder();
        try {
            devicesJSONArray = new JSONArray(serialPortFinder.getAllDevices());
        } catch (JSONException e) {
            Log.e("devices", "JSONException " + e.getMessage(), e);
            devicesJSONArray = new JSONArray();
        }
        devicesPath = serialPortFinder.getAllDevicesPath();

        try {
            ReaderHelper.setContext(mContext);
        } catch (Exception e) {
            Log.e("ReaderHelper", "setContext error " + e.getMessage(), e);
        }

    }

    /**
     * onDestroy
     */
    @Override
    public void onDestroy() {
        removeInventory6cListener();
        disConnect();

        /*
            关闭声音
         */
        Beeper.release();
        super.onDestroy();
    }

    /**
     * onReset
     */
    public void onReset() {
        removeInventory6cListener();
        disConnect();
        super.onReset();
    }

    /**
     * 如果当前你的插件代码没有和 UI 进行交互，或者有耗时的操作希望能运行在独立线程中，可以使用下面的代码：
     * cordova.getThreadPool().execute(new Runnable() {
     *
     * @Override public void run() {
     * // 你要执行的代码
     * }
     * });
     */
    @Override
//    public boolean execute(final String action, final CordovaArgs args, final CallbackContext callbackContext) {
//        cordova.getThreadPool().execute(new Runnable() {
//            @Override
//            public void run() {
//
//            }
//        });
    public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) {
        // 你要执行的代码
        if ("get_devices".equals(action)) {
            RfidPlugin.this.getDevices(args, callbackContext);
            return true;
        } else if ("connect_rs232".equals(action)) {
//            callbackContext.success(new JSONArray());
            RfidPlugin.this.connectRs232(args, callbackContext);
            return true;
        } else if ("inventory_6c_listener".equals(action)) {
            if (RfidPlugin.this.inventory6cCallbackContext != null) {
                removeInventory6cListener();
            }
            RfidPlugin.this.inventory6cCallbackContext = callbackContext;
            /*
                Don't return any result now,
                since status results will be sent when events come in from broadcast receiver
             */
            PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
            pluginResult.setKeepCallback(true);
            callbackContext.sendPluginResult(pluginResult);

            inventory6cRegisterReceiver();
            return true;
        } else if ("disConnect".equals(action)) {
            removeInventory6cListener();
            // release status callback in JS side
            this.inventory6cSendUpdate(new JSONObject(), false);
            this.inventory6cCallbackContext = null;

            RfidPlugin.this.disConnect();
            callbackContext.success("disConnect_success");
            return true;
        } else if ("refresh".equals(action)) {
            RfidPlugin.this.refresh(args, callbackContext);
            return true;
        } else if ("start_inventory_6c".equals(action)) {
            // 6c 标签开始盘存

//            refreshList();

            if (readerHelper.getInventoryFlag()) {
                mHandler.removeCallbacks(mRefreshRunnable);
                mHandler.postDelayed(mRefreshRunnable, 2000);
            }

//            refreshList();

//            RfidPlugin.this.localBroadcastManager = LocalBroadcastManager.getInstance(this);

            RfidPlugin.this.inventory(true, args);
            callbackContext.success("start_inventory_6c_success");
            return true;
        } else if ("stop_inventory_6c".equals(action)) {
            // 6c 标签结束盘存

            RfidPlugin.this.inventory(false, args);

            callbackContext.success("stop_inventory_6c_success");
            return true;
        }
        return false;
    }

    /**
     * We need to listen to the events to update the status
     */
    private void inventory6cRegisterReceiver() {
        if (this.inventory6cWebViewReceiver == null) {
            IntentFilter webViewIntentFilter = new IntentFilter();

            this.inventory6cWebViewReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    // do something
                }
            };
            webView.getContext()
                    .registerReceiver(this.inventory6cWebViewReceiver, webViewIntentFilter);
        }
    }

    /**
     * Create a new plugin result and send it back to JavaScript
     * @param info info
     * @param keepCallback keepCallback
     */
    private void inventory6cSendUpdate(JSONObject info, boolean keepCallback) {
        if (this.inventory6cCallbackContext != null) {
            PluginResult result = new PluginResult(PluginResult.Status.OK, info);
            result.setKeepCallback(keepCallback);
            this.inventory6cCallbackContext.sendPluginResult(result);
        }
    }

    /**
     * 获取所有串口数据
     */
    @TargetApi(Build.VERSION_CODES.KITKAT)
    private void getDevices(CordovaArgs args, CallbackContext callbackContext) {
        callbackContext.success(devicesJSONArray);
    }

    /**
     * 立即连接
     *
     * @param args (mPosPort, baud）
     */
    private void connectRs232(CordovaArgs args, CallbackContext callbackContext) {
        final String TAG = "COONECTRS232";
        int mPosPort = args.optInt(0);
        int baud = args.optInt(1);
        if (mPosPort < 0 || posPort.indexOf(baud) == -1) {
            callbackContext.error("rs232_error");
            return;
        }
        try {
            // 连接
            serialPort = new SerialPort(new File(devicesPath[mPosPort]), baud, 0);

            if (RfidPlugin.DEBUG) {
                Log.e(TAG, "ttys1 value :::" + devicesPath[mPosPort]);
            }

            try {
                readerHelper = ReaderHelper.getDefaultHelper();
                readerHelper.setReader(serialPort.getInputStream(), serialPort.getOutputStream());
            } catch (Exception e) {
                Log.e("rfidReaderHelper", "Exception " + e.getMessage(), e);
                callbackContext.error("error_unknown");
                return;
            }
            /*
                模块上电
             */
            if (!ModuleManager.newInstance().setUHFStatus(true)) {
                Log.e("RFID power", "UHF RFID power on failure, may you open in other" +
                        " Process and do not exit it");
                callbackContext.error("error_power on failure");
                return;
            }

            m_curInventoryBuffer = readerHelper.getCurInventoryBuffer();
            m_curReaderSetting = readerHelper.getCurReaderSetting();

            strEPCMap = new ConcurrentHashMap<String, Boolean>();

            callbackContext.success("connect_success");
        } catch (IOException e) {
            // *******************************
            // 弹窗或返回值：连接失败 "Connect failed!"
            callbackContext.error("connect_failed");
        } catch (SecurityException e) {
            callbackContext.error("error_security");
        } catch (InvalidParameterException e) {
            callbackContext.error("error_configuration");
        }
    }

    /**
     * 关闭连接
     */
    private void disConnect() {
//        if (moduleConnector.isConnected()) {
//            moduleConnector.disConnect();
//        }
        try {
            if (tcpSocket != null) {
                tcpSocket.close();
            }
            if (btSocket != null) {
                btSocket.close();
            }
        } catch (IOException e) {
            Log.e("disConnect", e.getMessage(), e);
        } finally {
            tcpSocket = null;
            btSocket = null;
        }

        if (serialPort != null) {
            if (RfidPlugin.DEBUG) {
                Log.e("close serial", "serial");
            }
            serialPort.close();
        }
        /*
            需要蓝牙权限
         */
        if (BluetoothAdapter.getDefaultAdapter() != null) {
            BluetoothAdapter.getDefaultAdapter().disable();
        }

        /*
            模块掉电，应用结束时建议掉电
         */
        ModuleManager.newInstance().setUHFStatus(false);
        /*
            释放模块上电掉电控制设备，退出应用的时候必须调用该方法，
            (2017/08/28之后的系统版本调用该方法还有掉电的作用)
         */
        ModuleManager.newInstance().release();
    }

    /**
     * 刷新
     */
    private void refresh(CordovaArgs args, CallbackContext callbackContext) {
        /*
            刷新数据
            default 0: 盘存标签 1: 存取标签
            6C 刷新
            6B
         */
        int index = args.optInt(0);
        String tagType = args.optString(1);
        switch (index) {
            case 0:
                if ("6C".equals(tagType)) {
                    if (m_curInventoryBuffer != null) {
                        m_curInventoryBuffer.clearInventoryRealResult();
                        strEPCMap.clear();
                        refreshList();
                    }
                }
//                    else if ("6B".equals(tagType)) {
//
//                    }
                break;
            case 1:
                break;
            default:
                callbackContext.error("refresh_error");
        }
        callbackContext.success("refresh_success");
    }
    //    private RFIDReaderHelper rfidReaderHelper;
    private static ReaderHelper readerHelper;
    private static ReaderBase mReader;

    private static InventoryBuffer m_curInventoryBuffer;

    private static ReaderSetting m_curReaderSetting;

    private boolean bTmpInventoryFlag = true;
    /**
     * 配置项：
     * 每条命令的盘存次数 default 1
     */
    private int realRoundText = 1;

//    private long mRefreshTime;

    /**
     * 已经存在的 strEPC
     */
    private ConcurrentHashMap<String, Boolean> strEPCMap;

    private void refreshList() {
        JSONObject jsonObj = new JSONObject();
        try {
            if (m_curInventoryBuffer.lsTagList != null) {
                List<String> strEPCList = new ArrayList<String>();
                List<InventoryBuffer.InventoryTagMap> inventoryTagMapList = new CopyOnWriteArrayList<InventoryBuffer.InventoryTagMap>(m_curInventoryBuffer.lsTagList);
                for (InventoryBuffer.InventoryTagMap tagMap : inventoryTagMapList) {
                    String strEPC = tagMap.strEPC;
                    Boolean hasEPC = strEPCMap.putIfAbsent(strEPC, true);
                    if (hasEPC == null) {
                        strEPCList.add(strEPC);
                    }
                }
                jsonObj.put("data", new Gson().toJson(strEPCList));
            }
        } catch (JSONException e) {
            LOG.e("inventory6cIntent", "JSONObject " + e.getMessage(), e);
        }
        inventory6cSendUpdate(jsonObj, true);
    }

    private boolean mReceiveFlag = true;

    private Handler mReceiveHandler = new Handler();

    private Runnable mReceiveRunnable = new Runnable() {
        public void run() {
            mReceiveFlag = true;
            mReceiveHandler.postDelayed(this, 2000);
        }
    };

    private Handler mHandler = new Handler();
    private Runnable mRefreshRunnable = new Runnable() {
        public void run() {
            /*
                刷新数据
             */
            refreshList();
            mHandler.postDelayed(this, 2000);
        }
    };
    private Handler mLoopHandler = new Handler();
    private Runnable mLoopRunnable = new Runnable() {
        public void run() {
            /*
             * byte btWorkAntenna =
             * m_curInventoryBuffer.lAntenna.get(m_curInventoryBuffer
             * .nIndexAntenna); if (btWorkAntenna < 0) btWorkAntenna = 0;
             * mReader.setWorkAntenna(m_curReaderSetting.btReadId,
             * btWorkAntenna);
             */
            readerHelper.runLoopInventroy();
            // 定时器 每两秒调用此 Runnable 对象
            mLoopHandler.postDelayed(this, 2000);
        }
    };

    /**
     * 开始结束存盘
     * @param args (start 是否开始存盘, ... 重复次数(待完善)）
     */
    private void inventory(boolean start, CordovaArgs args) {

        /*
            realRoundText 重复次数至少为1
         */
//        callbackContext.error("repeat_min");

        bTmpInventoryFlag = false;

        m_curInventoryBuffer.clearInventoryPar();
        /*
            至少需要选中一个天线
         */
        m_curInventoryBuffer.lAntenna.add((byte) 0x00);
//        if (m_curInventoryBuffer.lAntenna.size() <= 0) {
//            callbackContext.error("antenna_empty");
//            return;
//        }

        m_curInventoryBuffer.bLoopInventoryReal = true;

        m_curInventoryBuffer.btRepeat = (byte)realRoundText;

        /*
            高级选项选中 自定义 session 参数选中
         */
//        if (mCbRealSet.isChecked() && mCbRealSession.isChecked()) {
//            m_curInventoryBuffer.bLoopCustomizedSession = true;
//            m_curInventoryBuffer.btSession = (byte) (mPos1 & 0xFF);
//            m_curInventoryBuffer.btTarget = (byte) (mPos2 & 0xFF);
//        } else {
        m_curInventoryBuffer.bLoopCustomizedSession = false;
//        }

//        boolean start = args.optBoolean(0);
        // 停止
        if (start) {
//            refreshStartStop(true);
            // start_fixed by lei.li 2016/11/04 problem
            // m_curInventoryBuffer.clearInventoryRealResult();
            readerHelper.setInventoryFlag(true);
            // end_fixed by lei.li 2016/11/04
            readerHelper.clearInventoryTotal();

            byte btWorkAntenna = m_curInventoryBuffer.lAntenna
                    .get(m_curInventoryBuffer.nIndexAntenna);
            if (btWorkAntenna < 0) {
                btWorkAntenna = 0;
            }
            readerHelper.runLoopInventroy();
            m_curReaderSetting.btWorkAntenna = btWorkAntenna;
//            mRefreshTime = new Date().getTime();

            mLoopHandler.removeCallbacks(mLoopRunnable);
            mLoopHandler.postDelayed(mLoopRunnable, 2000);
            mHandler.removeCallbacks(mRefreshRunnable);
            mHandler.postDelayed(mRefreshRunnable, 2000);

//            refreshText();
        } else {
            readerHelper.setInventoryFlag(false);
            m_curInventoryBuffer.bLoopInventoryReal = false;

            mLoopHandler.removeCallbacks(mLoopRunnable);
            mHandler.removeCallbacks(mRefreshRunnable);

//            refreshStartStop(false);
//            refreshText();
            refreshList();
        }
    }
}
